import java.sql.*;
import java.util.*;

public class Main {
    private static final String URL = "jdbc:sqlite:identifier.sqlite";
    public static void main(String[] args) {
        Connection connection;
        List<Match> matches = new ArrayList<>();
        List<TeamStats> teamStats = new ArrayList<>();
        Map<Team,TeamStats> statsMap=new HashMap<>();
        Set<String> matchHistory = new HashSet<>();
        Set<List<String>> uniqueMatches = new HashSet<>();
        try {
            connection = DriverManager.getConnection(URL);
            String query = "SELECT * FROM swiss";
            try(PreparedStatement preparedStatement = connection.prepareStatement(query);
                ResultSet rs = preparedStatement.executeQuery()) {
                while(rs.next()) {
                    int matchID = rs.getInt("matchID");
                    Team team1 = Team.valueOf(rs.getString("team1"));
                    Team team2 = Team.valueOf(rs.getString("team2"));
                    Team winner = Team.valueOf(rs.getString("winner"));
                    Match match = new Match(matchID, team1, team2, winner);
                    matchHistory.add(getMatchKey(team1,team2));
                    matches.add(match);
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        for(Match match : matches){
            Team team1=match.getTeam1();
            Team team2=match.getTeam2();
            Team winner=match.getWinner();
            TeamStats team1Stats = statsMap.getOrDefault(team1,new TeamStats(team1));
            TeamStats team2Stats = statsMap.getOrDefault(team2,new TeamStats(team2));
            if(winner.equals(team1)){
                team1Stats.addWin();
                team2Stats.addLoss();
            }else {
                team2Stats.addWin();
                team1Stats.addLoss();
            }
            statsMap.put(team1,team1Stats);
            statsMap.put(team2,team2Stats);
            teamStats= new ArrayList<>(statsMap.values());
        }
        sortTeams(teamStats);
        displayTeams(teamStats);

        System.out.println("Next Round Draw Results");
        System.out.println("===================================");

        Map<Integer,List<TeamStats>> groupMap=preDraw(teamStats);
        draw(groupMap,matchHistory,uniqueMatches);
        System.out.println("===================================");
    }

    private static void sortTeams(List<TeamStats> teamStats){
        teamStats.sort((t1,t2)->{
            int winCompare=Integer.compare(t2.getWins(),t1.getWins());
            if (winCompare!=0){
                return winCompare;
            }else {
                return Integer.compare(t1.getLosses(),t2.getLosses());
            }
        });
    }
    private static void displayTeams(List<TeamStats> teamStats){
        System.out.println("===================================");
        System.out.println("Team Wins Losses Status");
        System.out.println("===================================");
        for(TeamStats teamStat:teamStats){
            System.out.println(teamStat);
        }
        System.out.println("===================================");
    }

    private static Map<Integer,List<TeamStats>> preDraw(List<TeamStats> teamStats){
        Map<Integer,List<TeamStats>> groupMap=new HashMap<>();
        for(TeamStats stats:teamStats){
            if(stats.getStatus()==Status.TBD){
                int wins=stats.getWins();
                groupMap.putIfAbsent(wins,new ArrayList<>());
                groupMap.get(wins).add(stats);
            }
        }
        return groupMap;
    }

    private static void draw(Map<Integer,List<TeamStats>> groupMap,Set<String> matchHistory,Set<List<String>> uniqueMatches){
        for(int wins:groupMap.keySet()){
            List<TeamStats> teams=groupMap.get(wins);
            for (int i=0;i<1000;i++){
                Set<String> matchesHistoryCopy=new HashSet<>(matchHistory);
                uniqueMatches.add(drawGroup(teams,matchesHistoryCopy));
            }
        }
        List<List<String>> uniqueMatchesList=new ArrayList<>(uniqueMatches);
        Collections.sort(uniqueMatchesList,(m1,m2)->{
            for (int i=0;i<m1.size();i++){
                int compare=m1.get(i).compareTo(m2.get(i));
                if (compare!=0){
                    return compare;
                }
            }
            return 0;
        });
        for(List<String> matches:uniqueMatchesList){
            System.out.println(matches);
        }
    }

    private static List<String> drawGroup(List<TeamStats> teams, Set<String> matchHistory) {
        List<String> matches = new ArrayList<>();
        Random random = new Random();
        Collections.shuffle(teams, random);
        for (int i = 0; i < teams.size(); i+=2) {
            if (i + 1 <= teams.size()) {
                Team team1 = teams.get(i).getTeam();
                Team team2 = teams.get(i + 1).getTeam();
                String matchKey = getMatchKey(team1, team2);
                if (matchHistory.contains(matchKey)) {
                    return drawGroup(teams, matchHistory);
                }else {
                    matches.add(matchKey);
                }
            }
        }
        Collections.sort(matches);
        return matches;
    }

    private static String getMatchKey(Team team1,Team team2){
        return team1.compareTo(team2)<0?team1+" vs "+team2:team2+" vs "+team1;
    }
}

class TeamStats{
    private Team team;
    private int wins;
    private int losses;
    private Status status=Status.TBD;

    public TeamStats(Team team){
        this.team = team;
    }

    public void addWin(){
        wins++;
        if (wins>=3){
            status=Status.Advanced;
        }
    }

    public void addLoss(){
        losses++;
        if (losses>=3){
            status=Status.Eliminated;
        }
    }

    public int getWins(){
        return wins;
    }

    public int getLosses(){
        return losses;
    }

    public Team getTeam(){
        return team;
    }

    public Status getStatus(){
        return status;
    }

    @Override
    public String toString(){
        return team + " " + wins + " " + losses + " " + status;
    }
}
